home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
eulisp
/
mpfeel.lha
/
MPFeel
/
specials.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-06
|
24KB
|
1,002 lines
/* ******************************************************************** */
/* specials.c Copyright (C) Codemist and University of Bath 1989 */
/* */
/* Language special forms (NOT toplevel forms) */
/* ******************************************************************** */
/*
* $Id: specials.c,v 1.10 1992/03/07 21:45:16 pab Exp $
*
* $Log: specials.c,v $
* Revision 1.10 1992/03/07 21:45:16 pab
* initial continuation changes
*
* Revision 1.9 1992/02/10 16:41:09 pab
* fixed dynamics properly
*
* Revision 1.8 1992/01/29 13:47:28 pab
* bindig fix, gc fix in dynamic let
*
* Revision 1.7 1992/01/09 22:29:05 pab
* Fixed for low tag ints
*
* Revision 1.6 1992/01/07 22:13:27 pab
* *** empty log message ***
*
* Revision 1.5 1992/01/05 22:48:20 pab
* Minor bug fixes, plus BSD version
*
* Revision 1.4 1991/12/22 15:14:34 pab
* Xmas revision
*
* Revision 1.3 1991/09/22 19:14:40 pab
* Fixed obvious bugs
*
* Revision 1.2 1991/09/11 12:07:40 pab
* 11/9/91 First Alpha release of modified system
*
* Revision 1.1 1991/08/12 16:50:00 pab
* Initial revision
*
* Revision 1.4 1991/02/13 18:28:55 kjp
* Pass.
*
*/
/*
* Change Log:
* Version 1, March 1990 (Compiler rationalisation)
* New fully working let/cc and unwind-protect -
* all stacks dealt with and dead continuations killed (KJP)
*/
#include "funcalls.h"
#include "defs.h"
#include "structs.h"
#include "error.h"
#include "global.h"
#include "funcalls.h"
#include "slots.h"
#include "garbage.h"
#include "symboot.h"
#include "modules.h"
#include "toplevel.h"
#include "root.h"
#include "allocate.h"
#include "specials.h"
#include "toplevel.h"
#include "state.h"
/*
* We're talking just the non-toplevel restricted special forms here
* like lambda, setq, and if - the ones always available.
*/
LispObject special_table;
LispObject my_make_special(LispObject *stacktop,
char *name, LispObject (*func)())
{
LispObject ans,tmp;
ans = (LispObject) get_symbol(stacktop,name);
STACK_TMP(ans);
tmp = (LispObject) allocate_special(stacktop,ans,func);
UNSTACK_TMP(ans);
ans->SYMBOL.lvalue=tmp;
STACK_TMP(ans);
EUCALL_3(tref_updator,special_table,ans,ans->SYMBOL.lvalue);
UNSTACK_TMP(ans);
return(ans->SYMBOL.lvalue);
}
EUFUN_1( Fn_special_form_p, name)
{
return(EUCALL_2(Fn_tref,special_table,name));
}
EUFUN_CLOSE
LispObject special_lambda;
EUFUN_3( Sf_lambda, mod, env, forms)
{
LispObject bvl,myforms;
LispObject ans,walker;
int i;
if (forms == nil) {
CallError(stacktop,"lambda: illegal empty lambda form",nil,NONCONTINUABLE);
}
myforms = forms;
bvl = CAR(myforms); myforms = CDR(myforms);
STACK_TMP(bvl); STACK_TMP(myforms);
walker = bvl; i = 0;
while (is_cons(walker)) {
walker = CDR(walker);
++i;
}
if (walker != nil) /* improper lambda list */
ans = (LispObject) allocate_i_function(stacktop,mod,env,-i -1);
else
ans = (LispObject) allocate_i_function(stacktop,mod,env,i);
UNSTACK_TMP(myforms); UNSTACK_TMP(bvl);
ans->I_FUNCTION.bvl = bvl;
ans->I_FUNCTION.body = myforms;
ans->I_FUNCTION.home = ARG_0(stackbase);
return ans;
}
EUFUN_CLOSE
LispObject special_macro_lambda;
EUFUN_3(Sf_mlambda, mod, env, forms)
{
LispObject bvl;
LispObject ans,walker;
int i;
if (forms == nil) {
CallError(stacktop,
"macro-lambda: illegal empty macro-lambda form",nil,NONCONTINUABLE);
}
bvl = CAR(forms); forms = CDR(forms);
ARG_2(stackbase)=forms;
walker = bvl; i = 0;
while (is_cons(walker)) {
walker = CDR(walker);
++i;
}
STACK_TMP(bvl);
if (walker != nil) /* improper lambda list */
ans = (LispObject) allocate_i_function(stacktop,mod,env,-i -1);
else
ans = (LispObject) allocate_i_function(stacktop,mod,env,i);
UNSTACK_TMP(bvl);
lval_typeof(ans) = TYPE_I_MACRO;
ans->I_MACRO.bvl = bvl;
ans->I_MACRO.body = ARG_2(stackbase)/*forms*/;
ans->I_MACRO.home = ARG_0(stackbase)/*mod*/;
return ans;
}
EUFUN_CLOSE
LispObject special_setq;
EUFUN_3( Sf_setq, mod, env, forms)
{
LispObject id;
if (forms == nil)
CallError(stacktop,"setq: illegal empty setq form",nil,NONCONTINUABLE);
id = CAR(forms); forms = CDR(forms);
if (!is_symbol(id))
CallError(stacktop,"setq: non-symbolic id",id,NONCONTINUABLE);
if (CDR(forms)!=nil)
CallError(stacktop,"setq: additional setq forms",nil,NONCONTINUABLE);
while (reserved_symbol_p(id)) {
id = CallError(stacktop,"setq: reserved symbol",id,CONTINUABLE);
}
STACK_TMP(id);
forms = EUCALL_3(module_eval,mod,env,CAR(forms));
UNSTACK_TMP(id);
STACK_TMP(forms);
STACK_TMP(id);
env=ARG_1(stackbase);
while (env != NULL) {
if (env->ENV.variable == id) {
if (env->ENV.mutable) return (env->ENV.value = forms);
if (EUCALL_2(Fn_equal, forms, env->ENV.value)==nil) {
CallError(stacktop,"setq: immutable binding",id,NONCONTINUABLE);
}
return forms;
}
env = (LispObject) env->ENV.next;
}
UNSTACK_TMP(id);
UNSTACK_TMP(forms);
/* Going for the module environment */
mod=ARG_0(stackbase);
STACK_TMP(forms);
(void) EUCALL_3(module_set,mod,id,forms); /* In the module handler */
return(forms);
}
EUFUN_CLOSE
LispObject special_progn;
EUFUN_3( Sf_progn, mod, env, forms)
{
LispObject ret;
if (!is_cons(forms))
CallError(stacktop,"progn: bad forms",forms,NONCONTINUABLE);
ret = nil; /* Null case return value */
while (is_cons(forms)) {
STACK_TMP(CDR(forms));
ret = EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,CAR(forms));
UNSTACK_TMP(forms);
}
return(ret);
}
EUFUN_CLOSE
LispObject special_if;
EUFUN_3( Sf_if, mod, env, forms)
{
LispObject pred,alt1,alt2;
LispObject debug;
debug = forms;
if (!is_cons(forms))
CallError(stacktop,"if: missing predicate",forms,NONCONTINUABLE);
pred = CAR(forms); forms = CDR(forms);
if (!is_cons(forms))
CallError(stacktop,"if: missing consequence",debug,NONCONTINUABLE);
alt1 = CAR(forms); forms = CDR(forms);
if (!is_cons(forms))
CallError(stacktop,"if: missing alternative",debug,NONCONTINUABLE);
alt2 = CAR(forms); forms = CDR(forms);
if (forms != nil)
CallError(stacktop,"if: extraneous forms",forms,NONCONTINUABLE);
STACK_TMP(alt1);
STACK_TMP(alt2);
if (EUCALL_3(module_eval,mod,env,pred) != nil) {
UNSTACK_TMP(alt1); UNSTACK_TMP(alt1);
return(EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,alt1));
}
else {
UNSTACK_TMP(alt2);
return(EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,alt2));
}
}
EUFUN_CLOSE
/*
* The continuation hacking special forms
*/
LispObject returned_continue_value;
LispObject last_continue;
LispObject target_continue; /* Used when unwinding... */
#define LETCC_DBG(x) /* x;fflush(stdout) */
LispObject special_letcc;
EUFUN_3( Sf_letcc, mod, env, forms)
{
LispObject id;
LispObject cont;
LispObject retval;
if (!is_cons(forms))
CallError(stacktop,"let/cc: weird argument",forms,NONCONTINUABLE);
if (!is_symbol(CAR(forms)))
CallError(stacktop,"let/cc: non-symbolic continuation name",id,NONCONTINUABLE);
/* OK, now do the business... */
cont = allocate_continue(stacktop);
STACK_TMP(cont);
if (set_continue(stacktop,cont)) {
/* We were resumed, return the value bit... */
UNSTACK_TMP(cont);
return(cont->CONTINUE.value);
}
UNSTACK_TMP(cont);
/* The hard bit's done - just add value to env... */
STACK_TMP(cont);
forms=ARG_2(stackbase);
id = CAR(forms); forms = CDR(forms);
STACK_TMP(forms);
env = allocate_envimut(stacktop,id,cont,ARG_1(stackbase));
UNSTACK_TMP(forms);
/* retval... */
retval = EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,env,forms);
/* Normal return - kill continuation... */
UNSTACK_TMP(cont);
unset_continue(cont);
return(retval);
}
EUFUN_CLOSE
void call_continuation(LispObject *stacktop,LispObject cont,LispObject value)
{
LispObject last;
LETCC_DBG(fprintf(stderr,"call cont: continuation invoked\n"));
/* First, check the continuation's still live... */
if (!cont->CONTINUE.live)
CallError(stacktop,"continuation call: dead continuation",cont,NONCONTINUABLE);
if (cont->CONTINUE.thread != CURRENT_THREAD())
CallError(stacktop,
"continuation call: not on this thread",cont,NONCONTINUABLE);
/* That's cool, now wander down (up?) the dynamic continuation list
killing stuff off and looking for unwind protects */
last = SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue);
while (last != cont) {
if (last == nil) {
fprintf(stderr,"AARRRRGGHHH!!!: continuation vanished!");
exit(1);
}
if (last->CONTINUE.unwind) {
LispObject temp;
/* We have an unwind continuation */
/* Leave interesting info for unwind-protect */
last->CONTINUE.target = cont;
last->CONTINUE.value = value;
/* Kill this unwind continuation */
temp = last;
last
= SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue)
= temp->CONTINUE.last_continue;
/* Jump... */
call_continue(stacktop,temp,value);
}
/* Normal continuation - kill it ! */
LETCC_DBG(fprintf(stderr,"call cont: killing middle continue\n"));
{
LispObject temp;
temp = last->CONTINUE.last_continue;
last->CONTINUE.live = FALSE;
last->CONTINUE.last_continue = nil;
last = SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue) = temp;
}
}
LETCC_DBG(fprintf(stderr,"call cont: hacking world\n"));
/* We've hit our own, so all is hunkydory */
/* Jump away... */
call_continue(stacktop,cont,value);
}
LispObject special_unwind_protect;
EUFUN_3( Sf_unwind_protect, mod, env, forms)
{
LispObject protected_form;
LispObject cont,value;
if (!is_cons(forms))
CallError(stacktop,"unwind-protect: invalid null argument",nil,NONCONTINUABLE);
protected_form = CAR(forms);
/* OK, want to set up an unwind marker */
cont = allocate_continue(stacktop); /* Allocate and freeze */
STACK_TMP(cont);
if (set_continue(stacktop,cont)) {
/* We've been invoked - run the tidy up forms... */
(void) EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,
CDR(ARG_2(stackbase))/* unwind_forms*/);
/* Got through that succesfully, so now try and find the target... */
UNSTACK_TMP(cont);
call_continuation(stacktop,cont->CONTINUE.target,cont->CONTINUE.value);
}
/* Mark the continuation as an unwind protect thing */
cont->CONTINUE.unwind = TRUE;
value = EUCALL_3(module_eval,ARG_0(stackbase),ARG_1(stackbase),CAR(ARG_2(stackbase)));
/* Kill off the continuation */
UNSTACK_TMP(cont);
unset_continue(cont);
/* Process the outward forms */
STACK_TMP(value);
(void) EUCALL_3(Sf_progn,ARG_0(stackbase),ARG_1(stackbase),CDR(ARG_2(stackbase)));
UNSTACK_TMP(value);
return(value);
}
EUFUN_CLOSE
/*
* Dynamics...
*/
LispObject special_dynamic_setq;
EUFUN_3( Sf_dynamic_setq, mod, env, forms)
{
LispObject id,form;
Env walker;
if (!is_cons(forms))
CallError(stacktop,"dynamic-setq: missing symbol",forms,NONCONTINUABLE);
id = CAR(forms); forms = CDR(forms);
if (!is_symbol(id))
CallError(stacktop,"dynamic-setq: non-symbolic reference",id,NONCONTINUABLE);
if (!is_cons(forms))
CallError(stacktop,"dynamic-setq: missing value form",forms,NONCONTINUABLE);
form = CAR(forms); forms = CDR(forms);
if (forms != nil)
CallError(stacktop,"dynamic-setq: extraneous forms",forms,NONCONTINUABLE);
walker = DYNAMIC_ENV();
while (walker != NULL) {
if (walker->variable == id)
{
STACK_TMP(walker);
form = EUCALL_3(module_eval,mod,env,form);
UNSTACK_TMP(walker);
return((walker->value = form));
}
walker = walker->next;
}
if (id->SYMBOL.gvalue == NULL) {
fprintf(stderr,"****Illegal assignment to undeclared variable: ");
EUCALL_2(Fn_print,id,StdErr);
fprintf(stderr,"****Implicit defvar used\n");
}
STACK_TMP(id);
form = EUCALL_3(module_eval,mod,env,form);
UNSTACK_TMP(id);
return((id->SYMBOL.gvalue = form));
}
EUFUN_CLOSE
EUFUN_2( Fn_dynamic_setq, id, form)
{
Env walker;
if (!is_symbol(id))
CallError(stacktop,"(setter symbol-dynamic-value): non-symbolic reference",id,NONCONTINUABLE);
walker = DYNAMIC_ENV();
while (walker != NULL) {
if (walker->variable == id) return((walker->value = form));
walker = walker->next;
}
if (id->SYMBOL.gvalue == NULL) {
fprintf(stderr,"****Illegal assignment to undeclared variable: ");
EUCALL_2(Fn_print,id,StdErr);
fprintf(stderr,"****Implicit defvar used\n");
}
return((id->SYMBOL.gvalue = form));
}
EUFUN_CLOSE
LispObject special_dynamic_set;
EUFUN_3( Sf_dynamic_set, mod, env, forms)
{
LispObject id,form;
Env walker;
if (!is_cons(forms))
CallError(stacktop,"dynamic-set: missing symbol",forms,NONCONTINUABLE);
id = CAR(forms); forms = CDR(forms);
id = EUCALL_3(module_eval,mod,env,id);
if (!is_symbol(id))
CallError(stacktop,"dynamic-set: non-symbolic reference",id,NONCONTINUABLE);
if (!is_cons(forms))
CallError(stacktop,"dynamic-set: missing value form",forms,NONCONTINUABLE);
form = CAR(forms); forms = CDR(forms);
if (forms != nil)
CallError(stacktop,"dynamic-set: extraneous forms",forms,NONCONTINUABLE);
STACK_TMP(id);
form = EUCALL_3(module_eval,mod,env,form);
UNSTACK_TMP(id);
walker = DYNAMIC_ENV();
while (walker != NULL) {
if (walker->variable == id) return((walker->value = form));
walker = walker->next;
}
if (id->SYMBOL.gvalue == NULL) {
fprintf(stderr,"****Illegal assignment to undeclared variable: ");
EUCALL_2(Fn_print,id,StdErr);
fprintf(stderr,"****Implicit defvar used\n");
}
return((id->SYMBOL.gvalue = form));
}
EUFUN_CLOSE
LispObject special_dynamic_let;
EUFUN_3( Sf_dynamic_let, mod, env, forms)
{
LispObject bindings;
Env save;
if (!is_cons(forms))
CallError(stacktop,"dynamic-let: null forms",forms,NONCONTINUABLE);
bindings = CAR(forms); forms = CDR(forms);
if (!is_cons(bindings))
CallError(stacktop,
"dynamic-let: invalid binding forms",bindings,NONCONTINUABLE);
save = DYNAMIC_ENV(); /* Hang on for exit... */
STACK_TMP(forms);
STACK_TMP(save);
while (is_cons(bindings)) {
LispObject id,val,bind;
LispObject xx;
bind = CAR(bindings);
STACK_TMP(CDR(bindings));
if (!is_cons(bind))
CallError(stacktop,
"dynamic-let: weird binding",bindings,NONCONTINUABLE);
id = CAR(bind); bind = CDR(bind);
if (!is_symbol(id))
CallError(stacktop,"dynamic-let: non-symbolic var",id,NONCONTINUABLE);
if (!is_cons(bind))
CallError(stacktop,"dynamic-let: weird binding",bindings,NONCONTINUABLE);
val = CAR(bind);
STACK_TMP(id);
val = EUCALL_3(module_eval,ARG_0(stackbase),ARG_1(stackbase),val);
UNSTACK_TMP(id);
xx = &(allocate_env(stacktop,id,val,
(LispObject)DYNAMIC_ENV())->ENV);
DYNAMIC_ENV()=xx;
UNSTACK_TMP(bindings);
}
UNSTACK_TMP(save);
UNSTACK_TMP(forms);
/* Do body... */
forms = EUCALL_3(Sf_progn,ARG_0(stackbase),ARG_1(stackbase),forms);
DYNAMIC_ENV() = save; /* Repoint */
return(forms);
}
EUFUN_CLOSE
EUFUN_1( Fn_dynamic, form)
{
{
Env ee = DYNAMIC_ENV();
while (ee!=NULL) {
if (ee->variable == form) return ee->value;
ee = ee->next;
}
}
{
LispObject ans;
ans = (form->SYMBOL).gvalue;
if (ans==NULL) { /* signal UNBOUND_DYNAMIC_VARIABLE */
ans = CallError(stacktop,"Unset dynamic variable ",form,CONTINUABLE);
(form->SYMBOL).gvalue = ans;
}
return ans;
}
}
EUFUN_CLOSE
LispObject special_dynamic;
EUFUN_3( Sf_dynamic, mod, env, form)
{
IGNORE(mod); IGNORE(env);
while (!is_symbol(CAR(form)) || CDR(form)!=nil)
form = CallError(stacktop,"dynamic: Illegal dynamic form ",form,CONTINUABLE);
form = CAR(form);
{
Env ee = DYNAMIC_ENV();
while (ee!=NULL) {
if (ee->variable == form) return ee->value;
ee = ee->next;
}
}
{
LispObject ans;
ans = (form->SYMBOL).gvalue;
if (ans==NULL) { /* signal UNBOUND_DYNAMIC_VARIABLE */
ans = CallError(stacktop,"dynamic: unset dynamic variable ",form,CONTINUABLE);
(form->SYMBOL).gvalue = ans;
}
return ans;
}
}
EUFUN_CLOSE
LispObject special_quote;
EUFUN_3( Sf_quote, mod, env, forms)
{
IGNORE(mod); IGNORE(env);
if (!is_cons(forms))
CallError(stacktop,"quote: bad forms",forms,NONCONTINUABLE);
return(CAR(forms));
}
EUFUN_CLOSE
/*
* Handlers...
*/
LispObject special_with_handler;
EUFUN_3( Sf_with_handler, mod, env, forms)
{
LispObject handler;
LispObject retval;
if (!is_cons(forms))
CallError(stacktop,
"with-handler: missing handler function",forms,NONCONTINUABLE);
handler = CAR(forms);
handler = EUCALL_3(module_eval,mod,env,handler);
if (!is_function(handler))
CallError(stacktop,
"with-handler: non-functional handler",handler,NONCONTINUABLE);
/* So far, so good - bung this onto the handler stack... */
HANDLER_STACK() = EUCALL_2(Fn_cons,handler,HANDLER_STACK());
/* Process the forms... */
retval = EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,CDR(ARG_2(stackbase)));
/* Unhitch the handler... */
HANDLER_STACK() = CDR(HANDLER_STACK());
return(retval);
}
EUFUN_CLOSE
/*******
* modified handler interactions
*
*******/
EUFUN_1(Fn_push_handler,handler)
{
HANDLER_STACK() = EUCALL_2(Fn_cons,handler,HANDLER_STACK());
return (HANDLER_STACK());
}
EUFUN_CLOSE
EUFUN_0(Fn_pop_handler)
{
HANDLER_STACK() = CDR(HANDLER_STACK());
return HANDLER_STACK();
}
EUFUN_CLOSE
/* I'll never write a complicated one (in C) */
EUFUN_1(Fn_simple_call_cc,fn)
{
LispObject cont;
LispObject args;
cont=allocate_continue(stacktop);
STACK_TMP(cont);
if (set_continue(stacktop,cont))
{ /* forcible return */
UNSTACK_TMP(cont);
return(cont->CONTINUE.value);
}
UNSTACK_TMP(cont);
STACK_TMP(cont);
args=EUCALL_2(Fn_cons,cont,nil);
return(EUCALL_2(module_mv_apply_1,ARG_0(stackbase)/*fn*/,args));
}
EUFUN_CLOSE
/* Hack... */
LispObject special_evalcm;
EUFUN_3(Sf_evalcm, mod, env, form)
{
LispObject ans;
if (!is_cons(form))
CallError(stacktop,"eval/cm: no arguments",form,NONCONTINUABLE);
if (is_cons(CDR(form)))
CallError(stacktop,"eval/cm: too many arguments",form,NONCONTINUABLE);
form = EUCALL_3(module_eval,mod,env,form);
ans = EUCALL_2(process_top_level_form,mod,CAR(form));
return(ans);
}
EUFUN_CLOSE
/* Tag Body... */
/*
* 'tagbody'
*
* Plan: Do a naive walk on the body to extract a table of symbols with
* following code, rig a continuation for 'go' statements to jump
* to and run them in sequence until done...
*/
/* ******************** This function cannot be called *************** */
static LispObject tagbody_before_label(LispObject *stacktop,LispObject body)
{
if (!is_cons(body)) return(nil);
if (is_symbol(CAR(body))) return(nil);
return(EUCALL_2(Fn_cons,CAR(body),tagbody_before_label(stacktop,CDR(body))));
}
static LispObject tagbody_suck_symbols(LispObject *stacktop,LispObject body)
{
if (!is_cons(body)) return(nil);
if (is_symbol(CAR(body))) return(tagbody_suck_symbols(stacktop,CDR(body)));
return(EUCALL_2(Fn_cons,CAR(body),tagbody_suck_symbols(stacktop,CDR(body))));
}
static LispObject tagbody_handle;
LispObject special_tagbody;
EUFUN_3( Sf_tagbody, mod, env, forms)
{
LispObject table,cont;
LispObject walker;
LispObject before;
LispObject res;
table = (LispObject) allocate_table(stacktop,Fn_eq);
STACK_TMP(table);
before = nil;
before = tagbody_suck_symbols(stacktop,forms);
STACK_TMP(before);
walker = forms;
while (is_cons(walker)) {
if (is_symbol(CAR(walker))) break;
walker = CDR(walker);
}
if (is_cons(walker)) {
Env augenv;
LispObject runbody;
/* Non-trivial label forms... */
cont = allocate_continue(stacktop);
STACK_TMP(cont);
do {
LispObject label, body;
label = CAR(walker); walker = CDR(walker);
body = tagbody_suck_symbols(stacktop,walker);
EUCALL_3(tref_updator,table,label,body);
while (is_cons(walker)) {
if (is_symbol(CAR(walker))) break;
walker = CDR(walker);
}
} while (is_cons(walker));
/* Construct the augmented environment... */
UNSTACK_TMP(cont);
augenv = (Env)allocate_env(stacktop,tagbody_handle,cont,env);
STACK_TMPV(augenv);
runbody = before;
reset:
/* Go continuation... */
if (set_continue(stacktop,cont)) {
/* Go has been called... */
runbody = EUCALL_2(Fn_tref,table,cont->CONTINUE.value);
if (runbody == nil)
CallError(stacktop,
"go: no such label",cont->CONTINUE.value,NONCONTINUABLE);
goto reset;
}
UNSTACK_TMPV(augenv);
STACK_TMP(cont);
res = EUCALL_3(Sf_progn,mod,(LispObject)augenv,runbody);
UNSTACK_TMP(cont);
unset_continue(cont);
return(res);
}
res = EUCALL_3(Sf_progn,mod,env,before);
return(res);
}
EUFUN_CLOSE
LispObject special_go;
EUFUN_3( Sf_go, mod, env, forms)
{
LispObject tag;
Env walker;
IGNORE(mod);
if (!is_cons(forms))
CallError(stacktop,"go: no tag",forms,NONCONTINUABLE);
tag = CAR(forms);
if (!is_symbol(tag))
CallError(stacktop,"go: non-symbolic tag",tag,NONCONTINUABLE);
walker = (Env)env;
while (walker != NULL) {
if (walker->variable == tagbody_handle)
call_continue(stacktop,walker->value,tag);
walker = walker->next;
}
CallError(stacktop,"go: not within tagbody",nil,NONCONTINUABLE);
return(nil);
}
EUFUN_CLOSE
void initialise_specials(LispObject *stacktop)
{
special_table = (LispObject) allocate_table(stacktop,Fn_eq);
add_root(&special_table);
special_lambda = my_make_special(stacktop,"lambda",Sf_lambda);
add_root(&special_lambda);
special_macro_lambda = my_make_special(stacktop,"macro-lambda",Sf_mlambda);
add_root(&special_macro_lambda);
special_setq = my_make_special(stacktop,"setq",Sf_setq);
add_root(&special_setq);
special_progn = my_make_special(stacktop,"progn",Sf_progn);
add_root(&special_progn);
special_if = my_make_special(stacktop,"if",Sf_if);
add_root(&special_if);
special_letcc = my_make_special(stacktop,"let/cc",Sf_letcc);
add_root(&special_letcc);
special_unwind_protect = my_make_special(stacktop,"unwind-protect",Sf_unwind_protect);
add_root(&special_unwind_protect);
/* last_continue = nil;*/
special_dynamic_setq = my_make_special(stacktop,"dynamic-setq",Sf_dynamic_setq);
add_root(&special_dynamic_setq);
special_dynamic_set = my_make_special(stacktop,"dynamic-set",Sf_dynamic_set);
add_root(&special_dynamic_set);
special_dynamic_let = my_make_special(stacktop,"dynamic-let",Sf_dynamic_let);
add_root(&special_dynamic_let);
special_dynamic = my_make_special(stacktop,"dynamic",Sf_dynamic);
add_root(&special_dynamic_let);
special_quote = my_make_special(stacktop,"quote",Sf_quote);
add_root(&special_quote);
special_with_handler = my_make_special(stacktop,"with-handler",Sf_with_handler);
add_root(&special_with_handler);
special_tagbody = my_make_special(stacktop,"tagbody",Sf_tagbody);
add_root(&special_tagbody);
tagbody_handle = get_symbol(stacktop,"***tagbody-handle***");
add_root(&tagbody_handle);
special_go = my_make_special(stacktop,"go",Sf_go);
add_root(&special_go);
}